<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        html,body{
            width: 100%;
            height: 100%;
            margin: 0;
            padding: 0;
        }
        body{
            display: flex;
            justify-content: center;
        }
        input{
            border: 0;
            padding: 0;
        }
        .app{
            width: 1024px;
            display: flex;
            flex-direction: column;
        }
        .path_container{
            width: 100%;
            height: 40px;
            background-color: darkgoldenrod;
            display: flex;
            align-items: center;
            padding-left: 10px;
            box-sizing: border-box;
        }
        .file_container{
            width: 100%;
            flex: 1;
            background-color: cadetblue;
        }
        .file_item{
            display: flex;
            flex-direction: row;
            align-items: center;
            height: 50px;
            transition: all 0.5s;
            color: white;
            cursor: pointer;
        }
        .file_item:hover{
            transition: all 0.5s;
            background-color: darkgray;
        }
        .file_item_column{
            display: flex;
            padding: 5px;
            flex-direction: row;
            align-items: center;
            justify-content: left;
            box-sizing: border-box;
        }
        .path_item{
            display: flex;
            justify-content: center;
            align-items: center;
            padding: 5px;
            box-sizing: border-box;
            border-radius: 5px;
            max-width: 15%;
        }
        .line_limit{
            display: inline-block;
            overflow: hidden;
            text-overflow: ellipsis;
            white-space: nowrap;
        }
        .path_path{
            transition: all 0.5s;
        }
        .path_path:hover{
            background-color: lightgray;
            transition: all 0.5s;
        }
        .cant_click_button{
            background-color: lightgray;
        }
        .file_header{
            width: 100%;
            display: flex;
            height: 40px;
            flex-direction: row;
            align-items: center;
        }
        .file_header_item{
            display: flex;
            flex-direction: row;
            align-items: center;
            justify-content: left;
            box-sizing: border-box;
            padding: 5px;
            background-color: white;
            height: 100%;
        }
        .menu_container{
            display: flex;
            flex-direction: row;
            align-items: center;
            justify-content: left;
        }
        .menu_button{
            box-sizing: border-box;
            padding: 10px 20px;
            display: flex;
            justify-content: center;
            align-items: center;
            border-radius: 5px;
            background-color: cadetblue;
            color: white;
            margin-right: 10px;
            cursor: pointer;
        }
    </style>
</head>
<body>
<div class="app">
    <div class="menu_container" id="menu_container">
        <div class="menu_button" onclick="createFolder()">新建文件夹</div>
        <div class="menu_button" onclick="selectFileUpload()">上传文件</div>
        <div class="menu_button" onclick="cut()" id="cut_button">剪切</div>
        <div class="menu_button" onclick="paste()" id="paste_button">粘贴</div>
        <div class="menu_button" onclick="share()" id="share_button">分享</div>
        <div class="menu_button" onclick="cancelShare()" id="cancel_share_button">取消共享</div>
        <div class="menu_button" onclick="delFile()" id="del_button">删除文件</div>
    </div>
    <div class="path_container" id="path_container"></div>
    <div class="file_container" id="file_container">
        <div class="file_header">
            <div class="file_header_item" style="width: 50%">名称</div>
            <div class="file_header_item" style="width: 30%">上传日期</div>
            <div class="file_header_item" style="width: 10%">类型</div>
            <div class="file_header_item" style="width: 10%">大小</div>
        </div>
        <div class="file_list_container" id="file_list_container">
<!--            <div class="file_item">-->
<!--                <div class="file_item_column" style="width: 50%">-->
<!--                    <input type="checkbox" style="margin-right: 5px"/>-->
<!--                    <img src="/img/file_icon.svg" width="20px" style="margin-right: 5px"/>-->
<!--                    <span style="margin-right: 5px">测试文件</span>-->
<!--                </div>-->
<!--                <div class="file_item_column" style="width: 30%">2022 3 12</div>-->
<!--                <div class="file_item_column" style="width: 10%">文件夹</div>-->
<!--                <div class="file_item_column" style="width: 10%">8K</div>-->
<!--            </div>-->
        </div>
    </div>
</div>
<script>
    class FileInfo{
        fileId;
        filePath;
        parentId;
        fileName;
        uploadTime;
        fileType;
        fileSize;
        shared;
        isDir(){
            return this.fileType==='dir';
        }
        isFile(){
            return this.fileType==='file';
        }
        static fromJson(json){
            let file=new FileInfo();
            file.fileId=json.id;
            file.fileName=json.fileName;
            file.fileType=json.fileType;
            file.fileSize=json.fileSize;
            file.parentId=json.parentId;
            file.shared=json.shared;
            file.uploadTime=json.uploadTime;
            return file;
        }
        static fromFolderJson(json){
            let file=new FileInfo();
            file.fileId=json.folderId;
            file.fileName=json.folderName;
            file.fileType='dir';
            file.filePath=json.folderPath;
            file.parentId=json.parentId;
            file.shared=json.shared;
            file.uploadTime=json.uploadTime;
            return file;
        }
        static newFolder(name,parentId){
            let file=new FileInfo();
            file.fileName=name;
            file.fileType='dir';
            file.parentId=parentId;
            return file;
        }
    }
    class Context{
        folder;
        parentFolder;
        files;
        clipboard;
        static newDefault(){
            let context=new Context();
            context.folder=null;
            context.parentFolder=null;
            context.files=[];
            context.clipboard=[];
            return context;
        }
    }
    function clipboardChanged(){
        let pasteButton=document.getElementById('paste_button');
        if (window.context.clipboard.length===0){
            pasteButton.style.backgroundColor="lightgray";
        }else{
            pasteButton.style.removeProperty('background-color')
        }
    }
    function cut(){
        let container=document.getElementById('file_list_container');
        let ids=[];
        for(let i=0;i<container.children.length;i++){
            let child=container.children[i];
            if (child.firstElementChild.firstElementChild.checked){
                ids.push(child.id);
                console.log("push");
            }
        }
        for(let i=0;i<ids.length;i++){
            for(let j=0;j<window.context.files.length;j++){
                let file=window.context.files[j];
                if (file.fileId===parseInt(ids[i])){
                    window.context.clipboard.push(file);
                }
            }
        }
        clipboardChanged();
    }
    function fileChecked(event){
        let container=document.getElementById('file_list_container');
        let checkedFileDom=null;
        for (let i=0;i<container.children.length;i++){
            if (container.children[i].contains(event.target)){
                checkedFileDom=container.children[i];
            }
        }
        if (checkedFileDom===null){
            return;
        }
        if (event.target.checked){
            checkedFileDom.style.backgroundColor='lightgray';
        }else{
            checkedFileDom.style.removeProperty('background-color');
        }
        checkChanged();
    }
    function checkChanged(){
        let shareFiles=[];
        let container=document.getElementById('file_list_container');
        for (let i=0;i<container.children.length;i++){
            if (container.children[i].firstElementChild.firstElementChild.checked){
                let id=container.children[i].id;
                for(let j=0;j<window.context.files.length;j++){
                    if (window.context.files[j].fileId===parseInt(id)){
                        shareFiles.push(window.context.files[j]);
                    }
                }
            }
        }
        let shareButton=document.getElementById('share_button');
        let cancelButton=document.getElementById('cancel_share_button');
        let delButton=document.getElementById('del_button');
        if (shareFiles.length===1){
            enableButton(shareButton);
        }else{
            disableButton(shareButton);
        }
        if (shareFiles.length>=1){
            enableButton(delButton);
        }
        if (shareFiles.length===0){
            disableButton(delButton);
        }
        if (shareFiles.length===1&&shareFiles[0].shared){
            enableButton(cancelButton);
        }else{
            disableButton(cancelButton);
        }
    }
    function delFile(){
        let button=document.getElementById('del_button');
        if (button.style.backgroundColor){
            return;
        }
        let itemIds=[];
        let container=document.getElementById('file_list_container');
        for(let i=0;i<container.children.length;i++){
            if (container.children[i].firstElementChild.firstElementChild.checked){
                itemIds.push(container.children[i].id);
            }
        }
        if (itemIds.length===0){
            alert("没有要取消的文件");
            return;
        }
        batchDel(itemIds).then(()=>{
            refresh(window.context.folder.fileId);
        })
    }


    function disableButton(buttonDom){
        buttonDom.style.backgroundColor='lightgray';
    }
    function enableButton(buttonDom){
        buttonDom.style.removeProperty('background-color');
    }
    async function paste() {
        console.log("paste")
        let targetDirId = window.context.folder.fileId;
        let context = await loadContext(targetDirId)
        for (let i = 0; i < window.context.clipboard.length; i++) {
            let item = window.context.clipboard[i];
            let exists=false;
            for(let j=0;j<context.files.length;j++){
                let targetDirFile=context.files[j];
                if (targetDirFile.fileName===item.fileName&&targetDirFile.fileType===item.fileType){
                    exists=true;
                }
            }
            let type=item.isDir()?"文件夹":"文件";
            if (exists){
                alert(type+" "+item.fileName+" 已存在");
            }else{
                let response=await moveApi(item.fileId,targetDirId)
                if (!response.ok){
                    handleError(response);
                }
            }
        }
        window.context.clipboard=[];
        refresh(window.context.folder.fileId);
    }

    function handleError(response){
        if (response.status===404){
            window.location.href="404.html";
        }else if(response.status===500){
            window.location.href='500.html';
        }
        response.text()
            .then((data)=>{
                alert(data);
            })
    }
    function batchDel(ids){
        let tasks=[];
        for(let i=0;i<ids.length;i++){
            tasks.push(delFileApi(ids[i]));
        }
        return Promise.all(tasks);
    }
    async function delFileApi(id){
        return fetch("/files/delete?fileId="+id)
            .then(response=>{
                if (!response.ok){
                    window.location.href="500.html";
                }
            })
    }
    async function listFileApi(id){
        let response=await fetch("/files?fileId="+id);
        if (!response.ok){
            handleError(response);
            return null;
        }
        let json=await response.json();
        let files=[];
        let responseFiles=json.subFiles;
        let folderPath=json.folderPath;
        for(let i=0;i<responseFiles.length;i++){
            let file=FileInfo.fromJson(responseFiles[i]);
            if (folderPath==='/'){
                file.filePath=folderPath+file.fileName;
            }else {
                file.filePath = folderPath + '/' + file.fileName;
            }
            files.push(file);
        }
        return files;
    }
    async function listFilesByPathApi(path){
        let response=await fetch("/files/path?path="+path);
        if (!response.ok){
            handleError(response);
            return null;
        }
        let json=await response.json();
        let files=[];
        let responseFiles=json.subFiles;
        let folderPath=json.folderPath;
        for(let i=0;i<responseFiles.length;i++){
            let file=FileInfo.fromJson(responseFiles[i]);
            if (folderPath==='/'){
                file.filePath=folderPath+file.fileName;
            }else {
                file.filePath = folderPath + '/' + file.fileName;
            }
            files.push(file);
        }
        return files;
    }
    async function getFolderById(id){
        let response=await fetch('/files?fileId='+id);
        if (!response.ok){
            handleError(response);
            return null;
        }
        let json=await response.json();
        return FileInfo.fromFolderJson(json);
    }
    async function getFolderByPath(path){
        let response=await fetch('/files/path?path='+path);
        if (!response.ok){
            handleError(response);
            return null;
        }
        let json=await response.json();
        return FileInfo.fromFolderJson(json);
    }
    async function moveApi(sourceId,targetDirId){
        return await fetch("/files/move?sourceId=" + sourceId + "&targetDirId=" + targetDirId);
    }
    async function shareApi(id,password){
        return await fetch("/files/share?fileId="+id+"&password="+password);
    }
    async function cancelShareApi(id){
        return await fetch("/files/share/cancel?fileId="+id);
    }
    async function newFileApi(file){
        let requestFileInfo={
            fileName:file.fileName,
            fileType:file.fileType,
            fileSize:file.fileSize,
            parentId:file.parentId,
        };
        let jsonData=JSON.stringify(requestFileInfo);
        let requestOptions = {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json'
            },
            body: jsonData
        };
        let response= await fetch("/files/new",requestOptions);
        if(!response.ok){
            handleError(response);
            return null;
        }
        let json=await response.json();
        let responseFile=new FileInfo();
        responseFile.fileId=json.id;
        responseFile.fileName=json.fileName;
        responseFile.fileType=json.fileType;
        responseFile.fileSize=json.fileSize;
        responseFile.parentId=json.parentId;
        responseFile.shared=json.shared;
        return responseFile;
    }
    async function loadContext(id){
        let files=await listFileApi(id);
        let folder=await getFolderById(id);
        let parentFolder=null;
        if (folder.parentId!==-1){
            parentFolder=await getFolderById(folder.parentId);
        }
        return {
            files:files,
            folder:folder,
            parentFolder:parentFolder
        }
    }
    async function loadContextFromPath(path){
        let files=await listFilesByPathApi(path);
        let folder=await getFolderByPath(path);
        let parentFolder=null;
        if (folder.parentId!==-1){
            parentFolder=await getFolderById(folder.parentId);
        }
        return {
            files:files,
            folder:folder,
            parentFolder:parentFolder
        }
    }

    function getPathOnPathContainer(container,target){
        let paths=[];
        let index=Array.from(container.children).indexOf(target);
        for(let i=0;i<=index;i++){
            let child=container.children[i];
            if (child.classList.contains('path_path')&&child.innerText!=='/'){
                paths.push(child);
            }
        }
        let path='/';
        for (let i=0;i<paths.length;i++){
            path+=paths[i].innerText;
            path+='/';
        }
        if (path!=='/') {
            path = path.slice(0, -1);
        }
        return path;
    }
    function renderDom(){
        invalidatePath();
        invalidateFiles();
        renderPath();
        renderFiles();
        checkChanged();
    }
    function invalidatePath(){
        let container=document.getElementById('path_container');
        let child=container.firstChild;
        while(child!==null){
            container.removeChild(child);
            child=container.firstChild;
        }
    }
    function invalidateFiles(){
        let container=document.getElementById('file_list_container');
        let child=container.firstChild;
        while(child!==null){
            container.removeChild(child);
            child=container.firstChild;
        }
    }
    function renderPath(){
        let path=window.context.folder.filePath;
        if (path.startsWith("/")&&path!=='/'){
            path=path.substring(1,path.length);
        }
        let paths=[];
        if (path!=='/'){
            paths=path.split('/');
        }
        let path_items=[];
        let first_item=document.createElement('div');
        first_item.classList.add('path_item');
        first_item.classList.add('line_limit');
        first_item.classList.add('path_path');
        first_item.innerText='/';
        path_items.push(first_item);
        for(let i=0;i<paths.length;i++){
            let path_item=document.createElement('div');
            path_item.classList.add('path_item');
            path_item.classList.add('line_limit');
            path_item.classList.add('path_path');
            path_item.innerText=paths[i];
            path_items.push(path_item);
        }

        for(let i=0;i<path_items.length;i++){
            let item=path_items[i];
            item.addEventListener('click',function (event){
                let container=document.getElementById('path_container');
                let target=event.target;
                if (target.classList.contains('path_path')){
                    let path=getPathOnPathContainer(container,target);
                    changeDirByPath(path);
                }
            })
        }

        let container=document.getElementById('path_container');
        for(let i=0;i<path_items.length;i++){
            let path_sep=document.createElement('div');
            path_sep.classList.add('path_item');
            let path_sep_img=document.createElement('img');
            path_sep_img.src="/img/right-arrow.svg";
            path_sep_img.style.width='10px';
            path_sep.appendChild(path_sep_img);
            container.appendChild(path_items[i]);
            container.appendChild(path_sep);
        }
        container.removeChild(container.lastChild);
    }
    function changeDirByPath(path){
        refreshByPath(path);
    }
    function changeDir(id){
        refresh(id);
    }
    function renderFiles(){
        let files=window.context.files;
        let container=document.getElementById('file_list_container');
        for (let i=0;i<files.length;i++){
            let file=files[i];
            let fileDom=document.createElement('div');
            fileDom.id=file.fileId;
            fileDom.classList.add('file_item');
            let fileColumnName=document.createElement('div');
            fileColumnName.style.width='50%';
            fileColumnName.classList.add('file_item_column');
            let fileColumnNameInput=document.createElement('input');
            fileColumnNameInput.style.marginRight='5px';
            fileColumnNameInput.setAttribute('type','checkbox');
            fileColumnNameInput.addEventListener('change',function (event){
                fileChecked(event);
            })
            let fileColumnNameImg=document.createElement('img');
            fileColumnNameImg.style.marginRight='5px';
            fileColumnNameImg.style.width='20px';
            if (file.isFile()){
                fileColumnNameImg.src='/img/file_icon.svg';
            }else{
                fileColumnNameImg.src='/img/folder.svg';
            }
            let fileColumnNameSpan=document.createElement('span');
            fileColumnNameSpan.style.marginRigh='5px';
            fileColumnNameSpan.innerText=file.fileName;

            fileColumnName.appendChild(fileColumnNameInput);
            fileColumnName.appendChild(fileColumnNameImg);
            fileColumnName.appendChild(fileColumnNameSpan);

            let fileColumnDate=document.createElement('div');
            fileColumnDate.style.width='30%';
            fileColumnDate.innerText=file.uploadTime;
            fileColumnDate.classList.add('file_item_column');


            let fileColumnType=document.createElement('div');
            fileColumnType.style.width='10%';
            fileColumnType.innerText=file.isDir()?"文件夹":"文件";
            fileColumnType.classList.add('file_item_column');


            let fileColumnSize=document.createElement('div');
            fileColumnSize.style.width='10%';
            fileColumnSize.innerText=file.fileSize;
            fileColumnSize.classList.add('file_item_column');

            fileDom.appendChild(fileColumnName);
            fileDom.appendChild(fileColumnDate);
            fileDom.appendChild(fileColumnType);
            fileDom.appendChild(fileColumnSize);

            if(file.isDir()){
                fileDom.addEventListener('dblclick',function (event){
                    let container=document.getElementById('file_list_container');
                    let targetFileId=null;
                    for(let i=0;i<container.children.length;i++){
                        let child=container.children[i];
                        if (child.contains(event.target)){
                            targetFileId=child.id;
                        }
                    }
                    if (targetFileId!==null){
                        changeDir(targetFileId);
                    }
                })
            }

            container.appendChild(fileDom);
        }
    }
    function refresh(id){
        loadContext(id)
            .then(context=>{
                window.context.files=context.files;
                window.context.folder=context.folder;
                window.context.parentFolder=context.parentFolder;
            })
            .then(()=>{
                renderDom();
            })
            .then(()=>{
                clipboardChanged();
            })
    }
    function refreshByPath(path){
        loadContextFromPath(path)
            .then(context=>{
                window.context.files=context.files;
                window.context.folder=context.folder;
                window.context.parentFolder=context.parentFolder;
            })
            .then(()=>{
                renderDom();
            })
            .then(()=>{
                clipboardChanged();
            })
    }
    window.onload=()=>{
        window.context=Context.newDefault();
        refresh(-1);
    }
    function createFolder(){
        let folderName=window.prompt("输入文件夹名")
        if (folderName===null){
            return;
        }
        if (folderName===''){
            alert("文件夹名不能为空");
            return;
        }
        if (folderName.includes('/')){
            alert("文件夹名内不能存在/");
            return;
        }
        let folder=FileInfo.newFolder(folderName,window.context.folder.fileId);
        newFileApi(folder)
            .then((newFile)=>{
                refresh(window.context.folder.fileId);
            })
    }
    function cancelShare(){
        let container=document.getElementById('file_list_container');
        let item=null;
        let itemId=null;
        for (let i=0;i<container.children.length;i++){
            if (container.children[i].firstElementChild.firstElementChild.checked){
                itemId=container.children[i].id;
            }
        }
        if (itemId===null){
            alert("没有要取消的文件");
            return;
        }
        for(let i=0;i<window.context.files.length;i++){
            if (window.context.files[i].fileId===parseInt(itemId)){
                item=window.context.files[i];
            }
        }
        if (item===null){
            alert("没有要取消的文件");
            return;
        }
        cancelShareApi(item.fileId)
            .then(response=>{
                if(!response.ok){
                    handleError(response);
                }
            })
            .then(()=>{
                refresh(window.context.folder.fileId);
            })
    }
    function share(){

        let button=document.getElementById('share_button');
        if (button.style.backgroundColor){
            return;
        }
        let item=null;
        let itemId=null;
        let container=document.getElementById('file_list_container');
        for(let i=0;i<container.children.length;i++){
            if (container.children[i].firstElementChild.firstElementChild.checked){
                itemId=container.children[i].id;
            }
        }
        for(let i=0;i<window.context.files.length;i++){
            if (window.context.files[i].fileId===parseInt(itemId)){
                item=window.context.files[i];
            }
        }
        if(itemId===null||item===null){
            alert("没有要分享的文件");
            return;
        }
        if (item.isDir()){
            alert("不支持分享文件夹");
            return;
        }
        let password=window.prompt("输入分享密码");
        if (password===null){
            return;
        }
        if (password===''){
            alert("输入密码不能为空");
            return;
        }
        shareApi(item.fileId,password)
            .then(response=>{
                if (!response.ok){
                    handleError(response);
                    return null;
                }else{
                    return response.json();
                }
            })
            .then(json=>{
                if (json!==null) {
                    let sharedFile = FileInfo.fromJson(json);
                    alert("文件的分享链接：" + "http://localhost:8080/sharePage?fileId=" + sharedFile.fileId);
                }
            })
            .then(()=>{
                refresh(window.context.folder.fileId);
            })
    }

    async function selectFileUpload(){
        let input=document.createElement('input');
        input.type='file';
        input.onchange=e=>{
            let file=e.target.files[0];
            let fileInfo=new FileInfo();
            fileInfo.fileName=file.name;
            fileInfo.fileType='file';
            fileInfo.fileSize=file.size;
            fileInfo.parentId=window.context.folder.fileId;
            newFileApi(fileInfo)
                .then(responseFile=>{
                    refresh(window.context.folder.fileId);
                })
        }
        input.click();
    }

</script>
</body>
</html>